package api;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.sun.xml.internal.ws.api.model.wsdl.WSDLOutput;
import common.CodeInVaildException;
import common.ProblemNotFoundException;
import compile.Answer;
import compile.Question;
import compile.Task;
import dao.Problem;
import dao.ProblemDAO;

import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;

@WebServlet("/compile")
public class CompileServlet extends HttpServlet {

    static class CompileRequest{
        public int id;
        public String code;
    }
    static class CompileResponse{
        //约定error为0表示编译ok，error为1表示编译出错，error为2运行出错，error为3表示为其他异常
        public  int error;
        public  String reason;
        public  String stdout;
    }
    private ObjectMapper objectMapper=new ObjectMapper();
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //获取到SmartTomcat的工作目录
        System.out.println("用户的当前工作目录："+System.getProperty("user.dir"));

        CompileRequest compileRequest=null;
        CompileResponse compileResponse=new CompileResponse();
       try{
           System.out.println("进入try块");
            resp.setStatus(200);
            resp.setContentType("application/json;charset=utf8");
            //1.先读取请求的正文。别按照JSON格式进行解析
            String body=readBody(req);
            compileRequest=objectMapper.readValue(body,CompileRequest.class);
            //2.根据id从数据库中查找到题目的详情=>得答案测试用例代码
            ProblemDAO problemDAO=new ProblemDAO();
            Problem problem= problemDAO.selectOne(compileRequest.id);
            if(problem==null){
                //为了统一处理错误，这里抛出一个异常
                throw new ProblemNotFoundException();
            }
            //testCode是测试用例的代码
            String testCode=problem.getTestCode();
            //requestCode是用户提交的代码
            String requestCode=compileRequest.code;
            //3.把用户提交的代码和测试用例的代码，给拼接成一个完整的代码
            String finalCode=mergeCode(testCode,requestCode);
            if(finalCode==null){
                throw new CodeInVaildException();
            }
            System.out.println(finalCode);
            //4.创建一个Task实例，调用里面的compileAndRun来进行编译运行
            Task task=new Task();
            Question question=new Question();
            question.setCode(finalCode);
            Answer answer=task.compileAndRun(question);
            //5.根据Task运行的结果，包装成一个HTTP响应
            compileResponse.error=answer.getError();
            compileResponse.reason=answer.getReason();
            compileResponse.stdout=answer.getStdout();
        } catch (ProblemNotFoundException e) {
            //处理题目没有找到的异常
           compileResponse.error=3;
           compileResponse.reason="题目没有找到 id="+compileRequest.id;
           String respString=objectMapper.writeValueAsString(compileResponse);
           resp.getWriter().write(respString);
        } catch (CodeInVaildException e) {
           compileResponse.error=3;
           compileResponse.reason="提交的代码不符合要求";
       }finally {
           String respString=objectMapper.writeValueAsString(compileResponse);
           resp.getWriter().write(respString);
       }
    }

    private static String mergeCode( String testCode ,String requestCode) {
        //1.查找requestCode中的最后一个}
        int pos=requestCode.lastIndexOf("}");
        if(pos==-1){
            //说明提交的代码完全没有}，错误代码
            return null;
        }
        //2.根据这个位置进行字符串截取
        String subStr=requestCode.substring(0,pos);
        //3.进行拼接
        return  subStr+testCode+"\n}";
    }

    private static String readBody(HttpServletRequest req) throws UnsupportedEncodingException {
        //1.先根据请求头里面的ContentLength 获取到body 的长度（单位是字节）
        int contentLength= req.getContentLength();
        //2.按照这个长度准备好一个byte[]
        byte[]buffer=new byte[contentLength];
        //3.通过req里面的getTputStream方法，获取到body的流对象
        try(ServletInputStream inputStream=req.getInputStream()) {
            //4.基于这个流对象，读取内容，然后把内容放到byte[]数组中即可
            inputStream.read(buffer);
        } catch (IOException e) {
            e.printStackTrace();
        }
        //5.把这个byte[]的内容构造成一个String
        return new String(buffer,"utf8");
    }
}
